package com.gengzp.system.service.impl;

import com.gengzp.common.enums.ConsolePageEnum;
import com.gengzp.common.enums.PermissionEnum;
import com.gengzp.common.enums.YesNoEnum;
import com.gengzp.common.exception.BusinessException;
import com.gengzp.common.model.permission.entity.UserRoleRelation;
import com.gengzp.common.model.permission.req.AllocatePageReq;
import com.gengzp.common.model.permission.req.AllocatePermissionReq;
import com.gengzp.common.model.permission.req.AllocateRoleReq;
import com.gengzp.common.model.permission.resp.SearchConsolePageResp;
import com.gengzp.common.model.permission.resp.SearchPermissionsResp;
import com.gengzp.common.model.role.entity.SysRole;
import com.gengzp.common.model.user.entity.SysUser;
import com.gengzp.permission.utils.PermissionUtils;
import com.gengzp.system.facade.SysRoleFacade;
import com.gengzp.system.facade.SysUserFacade;
import com.gengzp.system.mapper.UserRoleRelationMapper;
import com.gengzp.system.service.PermissionService;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName PermissionServiceImpl
 * @Description 权限管理服务层实现类
 * @Author gengzp
 * @Date 2025/9/15 15:44
 */
@Service
public class PermissionServiceImpl implements PermissionService {

    private static final Logger logger = LoggerFactory.getLogger(PermissionServiceImpl.class);

    @Autowired
    private SysRoleFacade sysRoleFacade;

    @Autowired
    private SysUserFacade sysUserFacade;

    @Autowired
    private UserRoleRelationMapper userRoleRelationMapper;

    @Override
    public SearchPermissionsResp searchAllPermissions() {
        // 获取所有权限枚举
        List<PermissionEnum> allPermissions = Arrays.asList(PermissionEnum.values());

        // 创建根节点（对应ROOT权限）
        SearchPermissionsResp rootResp = new SearchPermissionsResp();
        rootResp.setPermissionCode(PermissionEnum.ROOT.getCode());
        rootResp.setPermissionName("根节点");
        rootResp.setPermissionDescription("所有权限的顶级节点");

        // 递归构建子权限树
        rootResp.setChildrenPermissions(buildPermissionTree(
                PermissionEnum.ROOT.getCode(),
                allPermissions
        ));

        return rootResp;
    }

    @Override
    public List<SearchConsolePageResp> searchAllConsolePages() {
        return Arrays.stream(ConsolePageEnum.values()).map(v -> {
            SearchConsolePageResp resp = new SearchConsolePageResp();
            resp.setPageCode(v.getCode());
            resp.setPageName(v.getName());
            resp.setModule(v.getModule());
            return resp;
        }).toList();
    }

    @Override
    public void refreshRoleCache() {
        // 查出所有的系统角色
        List<SysRole> sysRoles = sysRoleFacade.searchAllSysRoles();
        if (CollectionUtils.isEmpty(sysRoles)) {
            PermissionUtils.removeAllCacheRoles();
        }

        // 系统中的所有角色id
        List<String> sysRoleIds = sysRoles.stream().map(v -> String.valueOf(v.getId())).toList();

        // 查询所有缓存中的角色id
        List<String> allCacheRoleIds = PermissionUtils.getAllCacheRoleIds();
        if (CollectionUtils.isNotEmpty(allCacheRoleIds)) {
            // 需要从缓存中移除的角色id
            List<String> removeCacheRoleIds = allCacheRoleIds.stream().filter(v -> !sysRoleIds.contains(v)).toList();
            if (CollectionUtils.isNotEmpty(removeCacheRoleIds)) {
                for (String removeCacheRoleId : removeCacheRoleIds) {
                    PermissionUtils.removeCacheRole(removeCacheRoleId);
                }
            }
        }

        // 将所有角色保存到缓存中
        for (SysRole sysRole : sysRoles) {
            PermissionUtils.assignCacheRolePermissions(sysRole.getId(),
                    Lists.newArrayList(sysRole.getPermissionCodes().split(",")), true);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocatePermissions(AllocatePermissionReq req) {
        // 要保存的权限编码集合
        List<String> savePermissionCodes = Lists.newArrayList();
        // 系统中不存在的权限编码集合
        List<String> nonexistentPermissionCodes = Lists.newArrayList();
        // 有子节点的权限编码集合
        Set<String> hasChildrenPermissionCodes = Sets.newHashSet();

        for (String permissionCode : req.getPermissionCodes()) {
            try {
                PermissionEnum permissionEnum = PermissionEnum.getByCode(permissionCode);
                if (Objects.nonNull(permissionEnum) &&
                        Objects.nonNull(permissionEnum.getParentPermission())) {
                    hasChildrenPermissionCodes.add(permissionEnum.getParentPermission().getCode());
                }
            } catch (Exception e) {
                nonexistentPermissionCodes.add(permissionCode);
            }
        }

        if (CollectionUtils.isNotEmpty(nonexistentPermissionCodes)) {
            throw BusinessException.get("权限编码不存在: " + String.join(",", nonexistentPermissionCodes));
        }
        savePermissionCodes.addAll(req.getPermissionCodes().stream().filter(v -> !hasChildrenPermissionCodes.contains(v)).toList());

        // 根据id查询系统角色
        SysRole sysRole = sysRoleFacade.searchSysRoleById(Long.valueOf(req.getRoleId()));
        if (Objects.isNull(sysRole)) {
            throw BusinessException.get(String.format("当前角色id: %s 不存在", req.getRoleId()));
        }

        // 角色权限信息落库
        sysRole.setPermissionCodes(CollectionUtils.isEmpty(savePermissionCodes) ? null :
                String.join(",", new HashSet<>(savePermissionCodes)));
        sysRoleFacade.editSysRoleById(sysRole);

        // 通过权限框架变更角色权限信息
        PermissionUtils.assignCacheRolePermissions(sysRole.getId(), savePermissionCodes, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocatePages(AllocatePageReq req) {
        if (CollectionUtils.isNotEmpty(req.getPageCodes())) {
            // 已经不存在了的页面权限列表
            List<String> nonExistentPageCodes = Lists.newArrayList();
            for (String pageCode : req.getPageCodes()) {
                if (Objects.isNull(ConsolePageEnum.getByCode(pageCode))) {
                    nonExistentPageCodes.add(pageCode);
                }
            }

            if (CollectionUtils.isNotEmpty(nonExistentPageCodes)) {
                throw BusinessException.get("本次分配的页面编码在系统中不存在： " +
                        String.join(",", nonExistentPageCodes));
            }
        }

        // 根据id查询系统角色
        SysRole sysRole = sysRoleFacade.searchSysRoleById(Long.valueOf(req.getRoleId()));
        if (Objects.isNull(sysRole)) {
            throw BusinessException.get(String.format("当前角色id: %s 不存在", req.getRoleId()));
        }

        sysRole.setConsolePageCodes(CollectionUtils.isEmpty(req.getPageCodes()) ? null :
                String.join(",", new HashSet<>(req.getPageCodes())));
        sysRoleFacade.editSysRoleById(sysRole);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocateRoles(AllocateRoleReq req) {
        Long userId = Long.valueOf(req.getUserId());

        // 查询要分配角色的用户
        SysUser sysUser = sysUserFacade.searchSysUserById(userId);
        if (Objects.isNull(sysUser)) {
            throw BusinessException.get("当前用户id不存在");
        }

        // 传入的角色id集合
        List<Long> roleIds = req.getRoleIds().stream().map(Long::valueOf).toList();
        if (CollectionUtils.isNotEmpty(roleIds) &&
                !Objects.equals(roleIds.size(), sysRoleFacade.searchSysRolesByIds(roleIds).size())) {
            throw BusinessException.get("分配的角色id有部分在系统中不存在");
        }

        // 查出用户已经存在的关联角色id
        List<Long> existRelationRoleIds = userRoleRelationMapper.selectRoleIdsByUserId(userId);
        // 要新增关联的角色id
        List<Long> willAddRoleIds = Lists.newArrayList();
        // 要删除关联的角色id
        List<Long> willRemoveRoleIds = Lists.newArrayList();

        if (CollectionUtils.isEmpty(existRelationRoleIds)) {
            willAddRoleIds.addAll(roleIds);
        } else {
            willAddRoleIds.addAll(roleIds.stream().filter(v -> !existRelationRoleIds.contains(v)).toList());
            willRemoveRoleIds.addAll(existRelationRoleIds.stream().filter(v -> !roleIds.contains(v)).toList());
        }

        // 添加角色关联
        if (CollectionUtils.isNotEmpty(willAddRoleIds)) {
            userRoleRelationMapper.batchInsertUserRoleRelations(willAddRoleIds.stream().map(v -> {
                UserRoleRelation userRoleRelation = new UserRoleRelation();
                userRoleRelation.setUserId(userId);
                userRoleRelation.setRoleId(v);
                userRoleRelation.setIsDeleted(YesNoEnum.NO.getCode());
                return userRoleRelation;
            }).collect(Collectors.toList()));
        }
        // 删除角色关联
        if (CollectionUtils.isNotEmpty(willRemoveRoleIds)) {
            userRoleRelationMapper.deleteUserRoleRelationsByUserIdAndRoleIds(userId, willRemoveRoleIds);
        }

        // 使用权限框架刷新用户角色的缓存
        PermissionUtils.assignCacheUserRoles(userId, roleIds, true);
    }

    /**
     * 递归构建权限树形结构
     *
     * @param parentCode     父权限编码
     * @param allPermissions 所有权限列表
     * @return 子权限列表
     */
    private List<SearchPermissionsResp> buildPermissionTree(String parentCode, List<PermissionEnum> allPermissions) {
        // 查找指定父权限下的所有子权限
        return allPermissions.stream()
                .filter(permission -> Objects.nonNull(permission.getParentPermission()) &&
                        parentCode.equals(permission.getParentPermission().getCode()))
                .map(permission -> {
                    // 转换为响应对象
                    SearchPermissionsResp resp = new SearchPermissionsResp();
                    resp.setPermissionCode(permission.getCode());
                    resp.setPermissionName(permission.getName());
                    resp.setPermissionDescription(permission.getDescription());
                    // 递归设置子权限
                    resp.setChildrenPermissions(buildPermissionTree(permission.getCode(), allPermissions));
                    return resp;
                })
                .collect(Collectors.toList());
    }

}
